#include "DocProcess.h"
#include "../AvatarLibrary.h"
#include <QFile>
#include <QtXml>
#include <QDebug>

DocProcess::DocProcess() {}

/**
 * @brief 加载引擎脚本文档
 */
void DocProcess::LoadAvatarDoc()
{
    QString document;
    AvatarLibrary::avatar_document(document);
    int start1 = document.indexOf("\r\n", document.indexOf("| :", document.indexOf("接口一览表"))) + 2;
    int start2 = document.indexOf("\r\n", document.indexOf("| :", document.indexOf("内置常量列表"))) + 2;
    QStringList lines = document.mid(start1, start2 - start1).split('\n');
    for (qsizetype i = 0; i < lines.length(); i++)
    {
        QString line = lines[i].trimmed();
        if (!line.startsWith("|")) break;
        while (line.startsWith('|')) line.remove(0, 1);
        while (line.endsWith('|')) line.remove(line.length() - 1, 1);
        QStringList doc = line.replace("\\|", "$").replace("*", "").replace("|", "*").replace("$", "|").split('*');
        QString name = doc[0].trimmed();
        insert(ScriptApiMap[name], std::make_shared<ScriptApi>(ScriptApi(name, doc[1].trimmed(), doc[2].trimmed(), doc[3].trimmed())));
    }
    // 常量表
    lines = document.mid(start2).split('\n');
    for (qsizetype i = 0; i < lines.length(); i++)
    {
        QString line = lines[i].trimmed();
        if (!line.startsWith("|")) break;
        while (line.startsWith('|')) line.remove(0, 1);
        while (line.endsWith('|')) line.remove(line.length() - 1, 1);
        QStringList doc = line.split('|');
        QString name = doc[0].trimmed();
        insert(ScriptApiMap[name], std::make_shared<ScriptApi>(ScriptApi(name, doc[1].trimmed())));
    }
}

/**
 * @brief 加载插件文档
 */
void DocProcess::LoadPluginDoc()
{
    QFile file(":/resource/doc/api_plugin_doc.xml");
    if (!file.open(QFileDevice::ReadOnly | QFile::Text)) return;
    QDomDocument doc;
    doc.setContent(&file);
    file.close();
    QDomElement document = doc.documentElement();
    QDomNodeList pluginList = document.elementsByTagName("plugin");
    for (int i = 0; i < pluginList.count(); i++)
    {
        QDomElement plugin = pluginList.at(i).toElement();
        QString pluginName = plugin.attribute("name");
        QDomNodeList functionList = plugin.elementsByTagName("function");
        for (int j = 0; j < functionList.count(); j++)
        {
            QDomElement function = functionList.at(j).toElement();
            QString name = function.attribute("name");
            QString desc = function.namedItem("desc").toElement().text();
            QString param = function.namedItem("param").toElement().text();
            QString ret = function.namedItem("ret").toElement().text();
            insert(ScriptApiMap[name], std::make_shared<ScriptApi>(ScriptApi(name, desc + "[" + pluginName + "]", param, ret)));
        }
    }
}

/**
 * @brief 加载场景节点文档
 */
void DocProcess::LoadSceneDoc()
{
    QFile file(":/resource/doc/api_node_doc.xml");
    if (!file.open(QFileDevice::ReadOnly | QFile::Text)) return;
    QDomDocument doc;
    doc.setContent(&file);
    file.close();
    QDomElement document = doc.documentElement();
    QDomNodeList nodeList = document.elementsByTagName("node");
    for (int i = 0; i < nodeList.count(); i++)
    {
        QDomElement node = nodeList.at(i).toElement();
        QString type = node.attribute("type");
        QDomNodeList functionList = node.elementsByTagName("function");
        for (int j = 0; j < functionList.count(); j++)
        {
            QDomElement function = functionList.at(j).toElement();
            QString name = function.attribute("name");
            QString desc = function.namedItem("desc").toElement().text();
            QString param = function.namedItem("param").toElement().text();
            QString ret = function.namedItem("ret").toElement().text();
            insert(SceneHandleMap[type], std::make_shared<ScriptApi>(ScriptApi(name, desc, param, ret)));
        }
    }
}

/**
 * @brief 将接口文档添加到脚本编辑器中
 * @param apis
 */
void DocProcess::AddAPI(QsciAPIs* apis)
{
    QMap<QString, QList<std::shared_ptr<ScriptApi>>>::iterator iter1 = ScriptApiMap.begin();
    while (iter1 != ScriptApiMap.end())
    {
        for (qsizetype i = 0; i < iter1.value().size(); i++)
        {
            apis->add(iter1.value()[i]->ToString());
        }
        ++iter1;
    }
    QMap<QString, QList<std::shared_ptr<ScriptApi>>>::iterator iter2 = SceneHandleMap.begin();
    while (iter2 != SceneHandleMap.end())
    {
        for (qsizetype i = 0; i < iter2.value().size(); i++)
        {
            std::shared_ptr<ScriptApi> api = iter2.value()[i];
            QString apiEntry = "'" + api->name + (api->param.isEmpty() ? "')" : "',{" + api->param + "})");
            apiEntry.remove(' ').replace(":string", "=''").replace(":number", "=0").replace(":integer", "=0").replace(":boolean", "=false").replace(":table", "={}");
            apiEntry += (api->ret.isEmpty() ? "" : " <= " + api->ret) + " --" + api->desc;
            apis->addUserEntry("scene.handle", iter2.key(), apiEntry);
        }
        ++iter2;
    }
}

/**
 * @brief 向API文档中加入文档项，拆分可变参数
 * @param apiList
 * @param api
 */
void DocProcess::insert(QList<std::shared_ptr<ScriptApi>>& apiList, std::shared_ptr<ScriptApi> api)
{
    if (api->param.contains(']'))
    {
        QStack<int> bracketStack;
        QList<QPair<int, int>> optionalRange;
        for (int i = 0; i < api->param.length(); i++)
        {
            char ch = api->param.at(i).toLatin1();
            if (ch == '[') bracketStack.push(i);
            else if (ch == ']') optionalRange.append(QPair<int, int>(bracketStack.pop(), i));
        }
        // 对于 X[A[B]][C] 需要拆分成 1-X 2-XA 3-XAB 4-XC
        QList<QList<QPair<int, int>>> groupRange;
        std::sort(optionalRange.begin(), optionalRange.end(), [](QPair<int, int>& a, QPair<int, int>& b) { return a.first < b.first; });
        int rangeEnd = -1;
        for (qsizetype i = 0; i < optionalRange.size(); i++)
        {
            if (optionalRange[i].first > rangeEnd)
            {
                rangeEnd = optionalRange[i].second;
                groupRange.append(QList<QPair<int, int>>());
            }
            groupRange.back().append(optionalRange[i]);
        }
        // 对可选区域进行组合
        QString fixedParam = api->param.mid(0, groupRange[0][0].first).trimmed();
        apiList.push_back(std::make_shared<ScriptApi>(api->name, api->desc, fixedParam, api->ret));
        for (qsizetype i = 0; i < groupRange.size(); i++)
        {
            QList<QPair<int, int>>& range = groupRange[i];
            for (qsizetype j = 0; j < range.size(); j++)
            {
                int start = range[0].first + 1;
                QString param = api->param.mid(start, (j + 1 == range.size() ? range[0].second : range[j + 1].first) - start);
                param = param.replace("[", "").replace("]", "").replace(" ,", ",").trimmed();
                apiList.push_back(std::make_shared<ScriptApi>(api->name, api->desc, fixedParam + param, api->ret));
            }
        }
    }
    else apiList.push_back(api);
}
